package com.sensetime.jv.service;

import cn.hutool.extra.spring.SpringUtil;
import com.sensetime.jv.entity.LoginUser;
import com.sensetime.jv.util.AssertUtil;
import com.sensetime.jv.util.JwtUtil;
import com.sensetime.jv.util.RedisCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

/**
 * Token Redis缓存服务，管理用户Token和用户信息缓存，有效期2小时
 */
@Service
public class TokenCacheService {

    @Value("${redis.cache.custom.tokenKey}")
    // Redis键前缀（避免键冲突）
    private String TOKEN_PREFIX;       // 存储Token：token:user:{userId} -> token值

    @Value("${redis.cache.custom.userInfoKey}")
    private String USER_INFO_PREFIX;    // 存储用户信息：user:info:{userId} -> LoginUser对象

    // Token 有效期（2小时）
    @Value("${redis.user.token.expiration}")
    private Integer EXPIRATION_TIME;

    @Autowired
    private RedisCache redisCache;  // 注入Redis工具类


    /**
     * 获取单例实例（Spring环境下推荐直接注入，此方法作为兼容）
     */
    public static TokenCacheService getInstance() {
        return SpringUtil.getBean(TokenCacheService.class);
    }


    /**
     * 生成并缓存新Token（同时缓存用户信息）
     *
     * @param userId        用户ID
     * @param loginUser
     * @param token
     * @return 生成的Token
     */
    public String generateToken(String userId, LoginUser loginUser, String token) {
        // 生成JWT Token
        if (StringUtils.isEmpty(token)) {
            token = generateUniqueToken(userId);
        }else {
            AssertUtil.hasText(token, "登录状态已过期，请重新登录");
        }
        // 缓存Token（设置过期时间）
        String tokenKey = getTokenKey(userId);
        redisCache.setCacheObject(tokenKey, token, EXPIRATION_TIME, TimeUnit.HOURS);

        // 缓存用户信息（与Token同有效期）
        String userInfoKey = getUserInfoKey(userId);
        redisCache.setCacheObject(userInfoKey, loginUser, EXPIRATION_TIME, TimeUnit.HOURS);

        return token;
    }


    /**
     * 根据用户ID获取有效的Token
     *
     * @param userId 用户ID
     * @return Token（未过期则返回，否则返回null）
     */
    public String getToken(String userId) {
        String tokenKey = getTokenKey(userId);
        return redisCache.getCacheObject(tokenKey);
    }


    /**
     * 根据用户ID获取缓存的用户信息
     *
     * @param userId 用户ID
     * @return LoginUser（未过期则返回，否则返回null）
     */
    public LoginUser getLoginUser(String userId) {
        // 先检查Token是否有效
        if (!isTokenValid(userId)) {
            return null;
        }
        String userInfoKey = getUserInfoKey(userId);
        return redisCache.getCacheObject(userInfoKey);
    }


    /**
     * 缓存用户信息（单独更新用户信息时使用）
     *
     * @param loginUser 用户信息
     */
    public void setUser(LoginUser loginUser) {
        if (loginUser == null || loginUser.getUser() == null) {
            return;
        }
        String userId = loginUser.getUser().getId().toString();
        String userInfoKey = getUserInfoKey(userId);
        // 与Token保持相同有效期
        redisCache.setCacheObject(userInfoKey, loginUser, EXPIRATION_TIME, TimeUnit.HOURS);
    }


    /**
     * 验证Token有效性（匹配+未过期）
     *
     * @param userId 用户ID
     * @param token  待验证的Token
     * @return 是否有效
     */
    public boolean validateToken(String userId, String token) {
        if (token == null) {
            return false;
        }
        String cachedToken = getToken(userId);
        // 比较Token是否一致，且Redis中存在（未过期）
        return token.equals(cachedToken);
    }


    /**
     * 刷新Token有效期（延长至2小时）
     *
     * @param userId 用户ID
     */
    public void refreshToken(String userId) {
        String tokenKey = getTokenKey(userId);
        String userInfoKey = getUserInfoKey(userId);

        // 刷新Token过期时间
        redisCache.expire(tokenKey, EXPIRATION_TIME, TimeUnit.HOURS);
        // 同步刷新用户信息过期时间
        redisCache.expire(userInfoKey, EXPIRATION_TIME, TimeUnit.HOURS);
    }


    /**
     * 注销用户的Token和缓存信息
     *
     * @param userId 用户ID
     */
    public void invalidateToken(String userId) {
        String tokenKey = getTokenKey(userId);
        String userInfoKey = getUserInfoKey(userId);

        // 删除Token缓存
        redisCache.deleteObject(tokenKey);
        // 删除用户信息缓存
        redisCache.deleteObject(userInfoKey);
    }


    /**
     * 删除指定用户的缓存信息（包括Token和用户信息）
     *
     * @param id 用户ID
     */
    public void removeUseInfo(Integer id) {
        if (id == null) {
            return;
        }
        invalidateToken(id.toString()); // 直接调用注销方法
    }


    /**
     * 检查Token是否有效（存在且未过期）
     */
    private boolean isTokenValid(String userId) {
        String tokenKey = getTokenKey(userId);
        // Redis中存在即有效（Redis会自动删除过期键）
        return redisCache.getCacheObject(tokenKey) != null;
    }


    /**
     * 生成唯一Token（基于JWT）
     */
    private String generateUniqueToken(String userId) {
        // 使用JWT生成包含用户ID的Token（有效期与Redis缓存一致）
        return JwtUtil.createToken(userId); // JWT有效期单位为毫秒
    }


    /**
     * 构建Token在Redis中的键
     */
    private String getTokenKey(String userId) {
        return TOKEN_PREFIX + userId;
    }


    /**
     * 构建用户信息在Redis中的键
     */
    private String getUserInfoKey(String userId) {
        return USER_INFO_PREFIX + userId;
    }

}